home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / sgml / msdos / sgml07 / entgen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-25  |  9.5 KB  |  401 lines

  1. /* entgen.c -
  2.  
  3.    Implement entgen() which generates a list of filenames from a struct fpi.
  4.    
  5.    Written by James Clark (jjc@jclark.com).
  6. */
  7.  
  8. #include "config.h"
  9.  
  10. #ifdef HAVE_ACCESS
  11.  
  12. #ifdef HAVE_UNISTD_H
  13. #include <unistd.h>        /* For R_OK. */
  14. #endif /* HAVE_UNISTD_H */
  15.  
  16. #ifndef R_OK
  17. #define R_OK 4
  18. #endif /* not R_OK */
  19.  
  20. #endif /* HAVE_ACCESS */
  21.  
  22. #include "sgmlaux.h"
  23.  
  24. /* Environment variable that contains path. */
  25. #ifndef PATH_ENV_VAR
  26. #define PATH_ENV_VAR "SGML_PATH"
  27. #endif
  28. /* Default search path.  See field() for interpretation of %*. */
  29. #ifndef DEFAULT_PATH
  30. #define DEFAULT_PATH "/usr/local/lib/sgml/%O/%C/%T:%N.%X:%N.%D"
  31. #endif
  32.  
  33. #ifndef PATH_FILE_SEP
  34. #define PATH_FILE_SEP ':'
  35. #endif
  36.  
  37. #ifndef SYSID_FILE_SEP
  38. #define SYSID_FILE_SEP ':'
  39. #endif
  40.  
  41. /* This says: change space to underscore, slash to percent. */
  42.  
  43. #ifndef MIN_DAT_SUBS_FROM
  44. #define MIN_DAT_SUBS_FROM " /"
  45. #endif
  46. #ifndef MIN_DAT_SUBS_TO
  47. #define MIN_DAT_SUBS_TO "_%"
  48. #endif
  49.  
  50. static int field P((struct fpi *, int, char *));
  51. static int mindatcpy P((char *, char *, int, int));
  52. static int testopen P((char *));
  53. static UNIV nentgen P((struct fpi *));
  54. static UNIV sysidgen P((char *));
  55.  
  56. static char *path = 0;
  57.  
  58. #define EMPTY_VERSION "default"
  59.  
  60. static char *classes[] = {
  61.      "capacity",
  62.      "charset",
  63.      "notation",
  64.      "syntax",
  65.      "document",
  66.      "dtd",
  67.      "elements",
  68.      "entities",
  69.      "lpd",
  70.      "nonsgml",
  71.      "shortref",
  72.      "subdoc",
  73.      "text"
  74.      };
  75.  
  76. /* This is mainly for compatibility with arcsgml. */
  77.  
  78. static char *genext[] = {
  79.      "nsd",  /* Non-SGML data entity. */
  80.      "gml",  /* GML document or text entity. */
  81.      "spe",  /* System parameter entity. */
  82.      "dtd",  /* Document type definition. */
  83.      "lpd",  /* Link process definition. */
  84.      "pns",  /* Public non-SGML data entity. */
  85.      "pge",  /* Public general entity. */
  86.      "ppe",  /* Public parameter entity. */
  87.      "pdt",  /* Public document type definition. */
  88.      "plp",  /* Public link process definition. */
  89.      "vns",  /* Display version non-SGML data entity. */
  90.      "vge",  /* Display version general entity. */
  91.      "vpe",  /* Display version parameter entity. */
  92.      "vdt",  /* Display version document type definition.*/
  93.      "vlp",  /* Display version link process definition.*/
  94. };
  95.  
  96. static char *ext[] = {
  97.      "sgml",            /* SGML subdocument */
  98.      "data",            /* Data */
  99.      "text",            /* General text */
  100.      "parm",            /* Parameter entity */
  101.      "dtd",            /* Document type definition */
  102.      "lpd",            /* Link process definition */
  103. };
  104.  
  105. /* Like memcpy, but substitute, fold to lower case (if fold is
  106. non-zero) and null terminate.  This is used both for minimum data and
  107. for names. If p is NULL, do nothing. Return len. */
  108.  
  109. static int mindatcpy(p, q, len, fold)
  110. char *p, *q;
  111. int len;
  112. int fold;
  113. {
  114.      static char subsfrom[] = MIN_DAT_SUBS_FROM;
  115.      static char substo[] = MIN_DAT_SUBS_TO;
  116.      int n;
  117.  
  118.      if (!p)
  119.       return len;
  120.      for (n = len; --n >= 0; q++) {
  121.       char *r = strchr(subsfrom, *q);
  122.       if (!r) {
  123.            if (fold && ISASCII(*q) && isupper((UNCH)*q))
  124.             *p++ = tolower((UNCH)*q);
  125.            else
  126.             *p++ = *q;
  127.       }
  128.       else {
  129.            int i = r - subsfrom;
  130.            if (i < sizeof(substo) - 1)
  131.             *p++ = substo[i];
  132.       }
  133.      }
  134.      *p = '\0';
  135.      return len;
  136. }
  137.  
  138.  
  139. /* Return length of field.  Copy into buf if non-NULL. */
  140.  
  141. static int field(f, c, buf)
  142. struct fpi *f;
  143. int c;
  144. char *buf;
  145. {
  146.      int n;
  147.  
  148.      switch (c) {
  149.      case '%':
  150.       if (buf) {
  151.            buf[0] = '%';
  152.            buf[1] = '\0';
  153.       }
  154.       return 1;
  155.      case 'N':            /* the entity, document or dcn name */
  156.       return mindatcpy(buf, (char *)f->fpinm, ustrlen(f->fpinm),
  157.             (f->fpistore != 1 && f->fpistore != 2 && f->fpistore != 3
  158.              ? NAMECASE
  159.              : ENTCASE));
  160.      case 'D':            /* dcn name */
  161.       if (f->fpistore != 1) /* not a external data entity */
  162.            return -1;
  163.       if (!f->fpinedcn == 0) /* it's a SUBDOC */
  164.            return -1;
  165.       return mindatcpy(buf, (char *)f->fpinedcn, ustrlen(f->fpinedcn),
  166.                           NAMECASE);
  167.      case 'X':
  168.       /* This is for compatibility with arcsgml */
  169.       if (f->fpistore < 1 || f->fpistore > 5)
  170.            return -1;
  171.       n = (f->fpipubis != 0)*(f->fpiversw > 0 ? 2 : 1)*5+f->fpistore - 1;
  172.       if (buf)
  173.            strcpy(buf, genext[n]);
  174.       return strlen(genext[n]);
  175.      case 'Y':            /* tYpe */
  176.       n = f->fpistore;
  177.       if (n < 1 || n > 6)
  178.            return -1;
  179.       if (n == 1 && f->fpinedcn == 0) /* it's a SUBDOC */
  180.            n = 0;
  181.       if (buf)
  182.            strcpy(buf, ext[n]);
  183.       return strlen(ext[n]);
  184.      case 'P':
  185.       if (!f->fpipubis)
  186.            return -1;
  187.       return mindatcpy(buf, (char *)f->fpipubis, ustrlen(f->fpipubis), 0);
  188.      }
  189.      /* Other fields need a formal public identifier. */
  190.      /* return -1 if the formal public identifier was invalid or missing. */
  191.      if (f->fpiversw < 0 || !f->fpipubis)
  192.       return -1;
  193.      
  194.      switch (c) {
  195.      case 'A':            /* Is it available? */
  196.       return f->fpitt == '+' ? 0 : -1;
  197.      case 'I':            /* Is it ISO? */
  198.       return f->fpiot == '!' ? 0 : -1;
  199.      case 'R':            /* Is it registered? */
  200.       return f->fpiot == '+' ? 0 : -1;
  201.      case 'U':            /* Is it unregistered? */
  202.       return f->fpiot == '-' ? 0 : -1;
  203.      case 'L':            /* public text language */
  204.       if (f->fpic == FPICHARS)
  205.            return -1;
  206.       /* it's entered in all upper case letters */
  207.       return mindatcpy(buf, (char *)f->fpipubis + f->fpil, f->fpill, 1);
  208.      case 'O':            /* owner identifier */
  209.       return mindatcpy(buf, (char *)f->fpipubis + f->fpio, f->fpiol, 0);
  210.      case 'C':            /* public text class */
  211.       n = f->fpic - 1;
  212.       if (n < 0 || n >= sizeof(classes)/sizeof(classes[0]))
  213.            return -1;
  214.       if (buf)
  215.            strcpy(buf, classes[n]);
  216.       return strlen(classes[n]);
  217.      case 'T':            /* text description */
  218.       return mindatcpy(buf, (char *)f->fpipubis + f->fpit, f->fpitl, 0);
  219.      case 'V':
  220.       if (f->fpic < FPICMINV)    /* class doesn't have version */
  221.            return -1;
  222.       if (f->fpiversw > 0)             /* no version */
  223.            return -1;
  224.       if (f->fpivl == 0) {        /* empty version: */
  225.                         /* use device-independent version*/
  226.            if (buf)
  227.             strcpy(buf, EMPTY_VERSION);
  228.            return strlen(EMPTY_VERSION);
  229.       }
  230.       return mindatcpy(buf, (char *)f->fpipubis + f->fpiv, f->fpivl, 0);
  231.      case 'S':                  /* public text designating (escape) sequence */
  232.       if (f->fpic != FPICHARS)
  233.            return -1;
  234.       return mindatcpy(buf, (char *)f->fpipubis + f->fpil, f->fpill, 0);
  235.      default:
  236.       break;
  237.      }
  238.      return -1;
  239. }
  240.  
  241. static int testopen(pathname)
  242. char *pathname;
  243. {
  244. #ifdef HAVE_ACCESS
  245.      return access(pathname, R_OK) >= 0;
  246. #else /* not HAVE_ACCESS */
  247.      FILE *fp;
  248.      fp = fopen(pathname, "r");
  249.      if (!fp)
  250.       return 0;
  251.      fclose(fp);
  252.      return 1;
  253. #endif /* not HAVE_ACCESS */
  254. }
  255.  
  256. /* Return a pointer to an dynamically-allocated buffer that contains
  257.    the names of the files containing this entity, with each filename
  258.    terminated by a '\0', and with the list of filenames terminated by
  259.    another '\0'. */
  260.  
  261. UNIV entgen(f)
  262. struct fpi *f;
  263. {
  264.      char *file;
  265.  
  266.      if (f->fpistore == 6)    /* a notation */
  267.       return nentgen(f);
  268.      if (f->fpisysis)
  269.       return sysidgen((char *)f->fpisysis);
  270.      if (!path) {
  271.       path = getenv(PATH_ENV_VAR);
  272.       if (!path)
  273.            path = DEFAULT_PATH;
  274.      }
  275.      file = path;
  276.      
  277.      for (;;) {
  278.       char *p;
  279.       int len = 0;
  280.       char *fileend = strchr(file, PATH_FILE_SEP);
  281.       if (!fileend)
  282.            fileend = strchr(file, '\0');
  283.  
  284.       /* Check that all substitutions are non-null, and calculate
  285.          the resulting total length of the filename. */
  286.       for (p = file; p < fileend; p++)
  287.            if (*p == '%') {
  288.             int n;
  289.             /* Set len to -1 if a substitution is invalid. */
  290.             if (++p >= fileend) {
  291.              len = -1;
  292.              break;
  293.             }
  294.             n = field(f, *p, (char *)0);
  295.             if (n < 0) {
  296.              len = -1;
  297.              break;
  298.             }
  299.             len += n;
  300.            }
  301.            else
  302.             len++;
  303.       
  304.       if (len > 0) {
  305.            /* We've got a valid non-empty filename. */
  306.            char *s;
  307.            char *buf;
  308.  
  309.            s = buf = (char *)rmalloc(len + 2);
  310.            for (p = file; p < fileend; p++)
  311.             if (*p == '%')
  312.              s += field(f, *++p, s);
  313.             else
  314.              *s++ = *p;
  315.            *s++ = '\0';
  316.            if (testopen(buf)) {
  317.             /* Terminate the array of filenames. */
  318.             *s++ = '\0';
  319.             return buf;
  320.            }
  321.            free((UNIV)buf);
  322.       }
  323.       if (*fileend == '\0')
  324.            break;
  325.       file = ++fileend;
  326.      }
  327.      return 0;
  328. }
  329.  
  330. /* If a system id is specified explicitly no searching is performed. */
  331.  
  332. static
  333. UNIV sysidgen(s)
  334. char *s;
  335. {
  336.      char *buf, *p;
  337.      
  338.      buf = (char *)rmalloc(strlen(s) + 2);
  339.  
  340.      for (p = buf; *s; s++) {
  341.       if (*s == SYSID_FILE_SEP) {
  342.            if (p > buf && p[-1] != '\0')
  343.             *p++ = '\0';
  344.       }
  345.       else if (*s == RECHAR)
  346.            *p++ = '\n';
  347.       else if (*s != RSCHAR)
  348.            *p++ = *s;
  349.      }
  350.      /* Terminate this filename. */
  351.      if (p > buf && p[-1] != '\0')
  352.       *p++ = '\0';
  353.      /* Terminate the list. */
  354.      *p++ = '\0';
  355.      return buf;
  356. }
  357.  
  358. /* Handle a notation identifier. */
  359.  
  360. static
  361. UNIV nentgen(f)
  362. struct fpi *f;
  363. {
  364.      UNS len;
  365.      char *buf, *p;
  366.  
  367.      if (f->fpisysis)
  368.       len = ustrlen(f->fpisysis);
  369.      else
  370.       len = mindatcpy((char *)0, (char *)f->fpinm , ustrlen(f->fpinm),
  371.               NAMECASE);
  372.      if (f->fpipubis)
  373.       len += ustrlen(f->fpipubis) + 1;
  374.      len += 2;
  375.      p = buf = (char *)rmalloc(len);
  376.      if (f->fpisysis) {
  377.       ustrcpy(p, f->fpisysis);
  378.       p += strlen(p) + 1;
  379.      }
  380.      else {
  381.       p += mindatcpy(p, (char *)f->fpinm, ustrlen(f->fpinm), NAMECASE);
  382.       *p++ = '\0';
  383.      }
  384.      if (f->fpipubis) {
  385.       ustrcpy(p, f->fpipubis);
  386.       p += strlen(p) + 1;
  387.      }
  388.      *p = '\0';
  389.      return buf;
  390. }
  391.  
  392. /*
  393. Local Variables:
  394. c-indent-level: 5
  395. c-continued-statement-offset: 5
  396. c-brace-offset: -5
  397. c-argdecl-indent: 0
  398. c-label-offset: -5
  399. End:
  400. */
  401.